package dev.ece.suit.text;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;

import dev.ece.util.lib.Vector4f;

public class RangeColorText {

	private int length;
	
	private RangeColorTextLine[] lines;
	
	private RangeColor[] ranges;
	
	private boolean rengeColors;
	
	private RangeColor currentRangeColor;
	
	private final Vector4f defaultColor = new Vector4f(1, 1, 1, 1);
	
	private RangeColorText() {}
	
	protected void glColor(TextLibShader textLibShader, int index) {
		if(rengeColors) {
			if(currentRangeColor != null) {
				if(currentRangeColor.isRangeColor(index)) {
					return;
				} else {
					textLibShader.glColor(defaultColor);
					currentRangeColor = null;
				}
			} 
			for(RangeColor rangeColor:ranges) {
				if(rangeColor.isRangeColor(index)) {
					currentRangeColor = rangeColor;
					textLibShader.glColor(rangeColor.getColor());
					return;
				}
			}
		}
	}
	
	public void render(TextLibShader shader, int startLineIndex, int lineLength, int length, float lineHeight) {
		if(startLineIndex < this.lines.length) {
			int index = Math.max(0, startLineIndex);
			int size = Math.min(startLineIndex + lineLength, lines.length);
			int charIndex = 0;
			int globalCharIndex = 0;
			float offset_y = - lineHeight / 2f;
			float offset_x = 0;
			float hwidth = 0;
			TextCharacter[] chars = null;
			TextCharacter ch = null;
			for(int i=0; i<index; i++) {
				globalCharIndex += this.lines[i].count();
			}
			for(int i=index; i<size; i++) {
				shader.glOffsetY(offset_y);
				chars = this.lines[i].getChars();
				offset_x = 0;
				for(int j=0; j<chars.length; j++) {
					if(charIndex < length) {
						ch = chars[j];
						hwidth = ch.getWidth() / 2f;
						offset_x += hwidth;
						shader.glOffsetX(offset_x);
						glColor(shader, globalCharIndex);
						ch.render(null, null);
						offset_x += hwidth;
					} else {
						return;
					}
					charIndex ++;
					globalCharIndex ++;
				}
				offset_y -= lineHeight;
			}
		}
	}
	
	public RangeColorTextLine[] getLines() {
		return lines;
	}

	public RangeColor[] getRanges() {
		return ranges;
	}

	public int length() {
		return length;
	}

	public boolean isRengeColors() {
		return rengeColors;
	}

	public Vector4f getDefaultColor() {
		return defaultColor;
	}

	public static RangeColorText createTangeColorText(String[] texts, TextLibrary textLibrary) {
		StringBuilder builder = new StringBuilder();
		for(String text: texts) {
			builder.append(text).append("\n");
		}
		return createTangeColorText(builder.toString(), textLibrary);
	}
	
	public static RangeColorText createTangeColorText(String text, TextLibrary textLibrary) {
		RangeColorText colorText = new RangeColorText();
		Pattern pattern = Pattern.compile(RangeColor.PATTERN_FONT_COLOR);
		String[] texts = createStringLines(pattern, text);
		int length = 0;
		RangeColorTextLine[] lines = new RangeColorTextLine[texts.length];
		for(int i=0; i<texts.length; i++) {
			lines[i] = RangeColorTextLine.createRangeColorTextLine(texts[i], textLibrary);
			length += lines[i].count();
		}
		colorText.ranges = createRangeColors(pattern, text);
		colorText.lines = lines;
		colorText.length = length;
		colorText.rengeColors = colorText.ranges.length > 0;
		return colorText;
	}
	
	private static String[] createStringLines(Pattern pattern, String text) {
		final StringBuilder builder = new StringBuilder();
		final Matcher matcher = pattern.matcher(text);
		int index = 0;
		String content = null;
		while(matcher.find()) {
			builder.append(StringUtils.substring(text, index, matcher.start()));
			content = matcher.group(2);
			builder.append(content);
			index = matcher.end();
		}
		String lines = text;
		if(index > 0) {
			builder.append(StringUtils.substring(text, index));
			lines = builder.toString();
		}
		return StringUtils.split(lines, "\n");
	}
	
	private static RangeColor[] createRangeColors(Pattern pattern, String text) {
		final Matcher matcher = pattern.matcher(StringUtils.remove(text, "\n"));
		int index = 0;
		List<RangeColor> rangeColorList = new ArrayList<RangeColor>();
		String color = null;
		String content = null;
		int start = 0;
		int end = 0;
		while(matcher.find()) {
			start += matcher.start() - index;
			color = matcher.group(1);
			content = matcher.group(2);
			end = start + content.length();
			rangeColorList.add(new RangeColor(start, end - 1, createFontColor(color)));
			start = end;
			index = matcher.end();
		}
		return rangeColorList.toArray(new RangeColor[] {});
	}
	
	public static Vector4f createFontColor(String color) {
		long num = Long.parseLong(color, 16);
		return new Vector4f(
				(float)(num & 0xFF0000) / 0xFF0000, 
				(float)(num & 0x00FF00) / 0x00FF00, 
				(float)(num & 0x0000FF) / 0x0000FF, 1.0f);
	}
	
}
